#人工智障
import time
import pygame
import random
import map_game
import button_event
from map_config import *
from button import *
import copy
import math
import AI_map  #AI专用地图
import sound

#导入win32api 用于弹出窗口
import win32api,win32con

from search_result import *

lastTime = int(time.time()*1000)
game_state = 0 #0为手动 1为AI

#0左 1右  2上 3下
def ai_find_direction():
    #dir = random.randint(0,3)  #人工智障1.0 随机数生成
    dir = lanmeng() #人工智障2.0 (贪心算法)
    #dir = lanmeng2() #人工智障3.0 (minimax算法 但经过试验 效果比2.0还要差 而且速度很慢所以放弃)
    return dir

#AI继续启动吧
def ai_2048_game_going(speed = 500):
    global lastTime
    global game_state
    if map_game.judge_gameover() == False and map_game.judge_gamewin() == False:
       #map_game.sound_flag = 0
        for event in pygame.event.get():
            #按钮事件检测
            button_event.buttonBase.check_event(event)
            button_event.buttonReturn.check_event(event)
            button_event.buttonAI.check_event(event)
            button_event.buttonTips.check_event(event)
            button_event.buttonReshow.check_event(event)

            if event.type == pygame.KEYDOWN:
                if(event.key == pygame.K_z):#Z键加快速度
                    if map_game.ai_delay_time > 50:
                        map_game.ai_delay_time = map_game.ai_delay_time - 50
                if(event.key == pygame.K_x):#X键减慢速度
                    if map_game.ai_delay_time < 1000:
                        map_game.ai_delay_time = map_game.ai_delay_time + 50

        thisTime = int(time.time()*1000)
        if thisTime - lastTime > speed:
            lastTime = int(time.time()*1000)
            dir = ai_find_direction()
            if dir == 0:
                map_game.go_move_left()
            elif dir == 1:
                map_game.go_move_right()
            elif dir == 2:
                map_game.go_move_up()
            elif dir == 3:
                map_game.go_move_down()
            else:
                game_state = 0 #跑不了了 你爱咋整咋整
    else:
        game_state = 0
        for event in pygame.event.get():
            #按钮事件检测
            button_event.buttonBase.check_event(event)
            button_event.buttonReturn.check_event(event)
            button_event.buttonAI.check_event(event)
            button_event.buttonTips.check_event(event)
            button_event.buttonReshow.check_event(event)

ii = 1
reshow_temp_buf = [ #缓存 记录
        [0,0,0,0],
        [0,0,0,0],
        [0,0,0,0],
        [0,0,0,0]
        ]

lstTime = int(time.time()*1000)
#回放模式
def reshow_mode(delaytime):
    global ii
    global lstTime
    global game_state
    tisTime = int(time.time()*1000)

    for event in pygame.event.get():
        #按钮事件检测
        button_event.buttonBase.check_event(event)
        button_event.buttonReturn.check_event(event)
        button_event.buttonAI.check_event(event)
        button_event.buttonTips.check_event(event)
        button_event.buttonReshow.check_event(event)

        if event.type == pygame.KEYDOWN:
            if(event.key == pygame.K_z):#Z键加快速度
                if map_game.ai_delay_time > 50:
                    map_game.ai_delay_time = map_game.ai_delay_time - 50
            if(event.key == pygame.K_x):#X键减慢速度
                if map_game.ai_delay_time < 1000:
                    map_game.ai_delay_time = map_game.ai_delay_time + 50

    if tisTime - lstTime > delaytime:
        lstTime = int(time.time()*1000)
        cc = copy.deepcopy(map_game.board_stack)
        if ii < len(cc):
            map_game.board = copy.deepcopy(cc[ii])
            ii = ii + 1
            sound.slide_sound()
        else:
            map_game.board = copy.deepcopy(reshow_temp_buf)
            game_state = 0
            sound.stop_sound()
            sound.background_sound()

#独创AI算法(人工智障2.0)
#贪心算法：
#从四个方向遍历 并获取移动后的格局值 四个方向哪个方向的格局值最大就选哪一个
def lanmeng():
    dir_num = [0,0,0,0]
    TestAIBoard = AI_map.AIMap(map_game.board)
    for direction in range(0,4):#四个方向都遍历一遍
        TestAIBoard2 = AI_map.AIMap(TestAIBoard.map)
        if TestAIBoard2.ai_go(direction) == False:#走不了就滚蛋吧
            dir_num[direction] = -999999
        else:
            dir_num[direction] = sum(TestAIBoard2.ai_evaluation())#将分析的结果加起来

    if max(dir_num) == -999999:
        return -1
    else:
        return dir_num.index(max(dir_num)) #选取得分最高的一个

#独创AI算法(人工智障3.0)
#minimax算法
# 定义搜索结果类，用于方便处理返回值
class searchResult:
    def __init__(self, move=-1, score=0, positions=0, cutoffs=0) -> None:
        self.move = move
        self.positions = positions
        self.cutoffs = cutoffs
        self.score = score

def search(thisBoard: AI_map.AIMap, depth, alpha, beta, positions, cutoffs, playerTurn: bool):
    bestScore = 0
    bestMove = -1
    result = searchResult()
    if playerTurn == True:  #玩家回合 倾向于让玩家获得最多的分数
        bestScore = alpha  # 最高分为alpha
        for direction in range(4):  # 四个方向分别进行遍历
            newBoard = AI_map.AIMap(thisBoard.map)  # 新建一个棋盘防止影响到正式游戏
            changed = newBoard.ai_go(direction)  # 相对应方向移动
            if changed == True:  # 如果这个方向可以移动
                positions += 1  # positions自增
                if depth == 0:  # 如果已经搜索到最底层了
                    result.move = direction
                    result.score = sum(newBoard.ai_evaluation())  # 返回当前局面的评价值
                else:
                    result = search(newBoard, depth-1, bestScore, beta, positions, cutoffs, False)  # 进行min轮，即让AI下出对局面最不利的一步
                    if result.score > 9900:
                        result.score -= 1
                    positions = result.positions
                    cutoffs = result.cutoffs  # 将返回值进行处理

                if result.score > bestScore:
                    bestScore = result.score
                    bestMove = direction

                if bestScore > beta:  # 如果最高值大于beta，则已经证明该走法优于前面的最优，则本深度下后面不用继续计算。
                    cutoffs += 1
                    return searchResult(bestMove, beta, positions, cutoffs)
    else:   #AI回合 倾向于让玩家获得最少的分数
        bestScore = beta
        newBoard = AI_map.AIMap(thisBoard.map)
        score_2 = []
        score_4 = []
        worstSituation = []
        cells = []
        for i in range(4):    #找到空格子
            for j in range(4):
                if newBoard.map[i][j] == 0:
                    cells.append([i, j])

        for value in [2, 4]:  #生成可能的所有情况，并进行评估
            for i in range(len(cells)):
                if newBoard.map[cells[i][0]][cells[i][1]] == 0:
                    newBoard.map[cells[i][0]][cells[i][1]] = value
                    if value == 2:
                        score_2.append(-newBoard.smothness() + newBoard.islands())
                    if value == 4:
                        score_4.append(-newBoard.smothness() + newBoard.islands())
                    newBoard.map[cells[i][0]][cells[i][1]] = 0

        maxScore = max(max(score_2), max(score_4))  #找到最差的情况
        for i in range(len(score_2)):  # 最差的情况可能不止一种，所以遍历一遍防止遗漏
            if score_2[i] == maxScore:
                worstSituation.append([cells[i], 2])
        for i in range(len(score_4)):
            if score_4[i] == maxScore:
                worstSituation.append([cells[i], 4])
        for situation in worstSituation:  # 遍历所有最差情况
            nnewBoard = AI_map.AIMap(thisBoard.map)
            positions += 1
            result = search(nnewBoard, depth, alpha, bestScore, positions, cutoffs, True)  # 进一步搜索
            positions = result.positions
            cutoffs = result.cutoffs

            if result.score < bestScore:
                bestScore = result.score

            if bestScore < alpha:  # 剪枝同理
                cutoffs += 1
                return searchResult(-1, alpha, positions, cutoffs)

    return searchResult(bestMove, bestScore, positions, cutoffs)

def lanmeng2():
    depth = 3
    nAIMap = AI_map.AIMap(map_game.board)
    newBest = search(nAIMap, depth, -1000000, 1000000, 0, 0, True)
    return newBest.move

#以下为回调函数
#
#
#
#
#
#
#
#
#AI按键回调函数
def ai_button_callback():
    sound.stop_sound()
    global game_state
    if game_state == 0:
        game_state = 1
        sound.ai_background_sound()
    else:
        game_state = 0
        sound.background_sound()

#提示模式按键回调函数
def tips_button_event():
    tips_direction = ai_find_direction()
    if tips_direction == 0:
        win32api.MessageBox(0,"下一步应该：往左","提示",win32con.MB_OK)
    elif tips_direction == 1:
        win32api.MessageBox(0,"下一步应该：往右","提示",win32con.MB_OK)
    elif tips_direction == 2:
        win32api.MessageBox(0,"下一步应该：往上","提示",win32con.MB_OK)
    elif tips_direction == 3:
        win32api.MessageBox(0,"下一步应该：往下","提示",win32con.MB_OK)
    else:
        win32api.MessageBox(0,"走不了了","提示",win32con.MB_OK)

#回放功能回调函数
def reshow_callback():
    sound.stop_sound()
    global game_state
    global ii
    global reshow_temp_buf
    if game_state != 2:
        sound.reshow_sound()
        game_state = 2  #不管什么模式进去就是回放模式
        ii = 1
        reshow_temp_buf = copy.deepcopy(map_game.board) #缓存下来